package timing.ukulele.seal.service.minio;

import io.minio.*;
import io.minio.errors.*;
import io.minio.messages.Bucket;
import io.minio.messages.Item;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.List;

/**
 * 存储桶的相关操作封装
 */
@Service
public class BucketService {
    private final MinioClient client;

    public BucketService(MinioClient client) {
        this.client = client;
    }

    /**
     * 创建一个新的存储桶
     *
     * @param bucketName String  存储桶名称
     * @throws IOException               连接异常
     * @throws InvalidKeyException
     * @throws InvalidResponseException
     * @throws NoSuchAlgorithmException  找不到相应的签名算法
     * @throws InsufficientDataException 在读到相应length之前就得到一个EOFException
     * @throws ServerException
     * @throws ErrorResponseException    执行失败
     * @throws InternalException         内部异常
     * @throws XmlParserException
     */
    public void makeBucket(String bucketName) throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException,
            ServerException, InternalException, XmlParserException, ErrorResponseException {
        client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
    }

    /**
     * 列出所有存储桶
     *
     * @return List<Bucket> 存储桶列表
     * @throws IOException               连接异常
     * @throws InvalidKeyException       不合法的access key或者secret key
     * @throws NoSuchAlgorithmException  找不到相应的签名算法
     * @throws InsufficientDataException 在读到相应length之前就得到一个EOFException
     * @throws InternalException         内部异常
     * @throws ErrorResponseException    执行失败
     * @throws XmlParserException
     * @throws ServerException
     * @throws InvalidResponseException
     */
    public List<Bucket> listBuckets() throws IOException, InvalidKeyException, NoSuchAlgorithmException, InsufficientDataException, InternalException,
            ErrorResponseException, XmlParserException, ServerException, InvalidResponseException {
        List<Bucket> bucketList = client.listBuckets();
        return bucketList;
    }

    /**
     * 检查存储桶是否存在
     *
     * @param bucketName 存储桶名称
     * @return Boolean true存在   false不存在
     * @throws IOException               连接异常
     * @throws InvalidKeyException       不合法的access key或者secret key
     * @throws NoSuchAlgorithmException  找不到相应的签名算法
     * @throws InsufficientDataException 在读到相应length之前就得到一个EOFException
     * @throws InternalException         内部异常
     * @throws ErrorResponseException    执行失败
     * @throws InvalidResponseException
     * @throws XmlParserException
     */
    public boolean bucketExists(String bucketName) throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException,
            ServerException, InternalException, XmlParserException, ErrorResponseException {
        boolean found = client.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
        return found;
    }

    /**
     * 删除一个存储桶
     * TODO 文档中以下两个说法待验证
     * 注意，只有存储桶为空时才能删除成功
     * 注意: - removeBucket不会删除存储桶里的对象，你需要通过removeObject API来删除它们
     *
     * @param bucketName 存储桶名称
     * @throws IOException               连接异常
     * @throws InvalidKeyException       不合法的access key或者secret key
     * @throws NoSuchAlgorithmException  找不到相应的签名算法
     * @throws InsufficientDataException 在读到相应length之前就得到一个EOFException
     * @throws InternalException         内部异常
     * @throws ErrorResponseException    执行失败
     * @throws InvalidResponseException
     * @throws ServerException
     * @throws XmlParserException
     */
    public void removeBucket(String bucketName) throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException,
            NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, ErrorResponseException {
        boolean found = client.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
        if (found) {
            client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
        }
    }

    /**
     * 列出某个存储桶中的所有对象
     *
     * @param bucketName  存储桶名称
     * @param prefix      对象名称的前缀
     * @param recursive   是否递归查找，如果是false,就模拟文件夹结构查找
     * @param useVersion1 如果是true, 使用版本1 REST API
     * @return Iterable<Result < Item>>  对象列表
     * @throws IOException               连接异常
     * @throws InvalidKeyException       不合法的access key或者secret key
     * @throws NoSuchAlgorithmException  找不到相应的签名算法
     * @throws InsufficientDataException 在读到相应length之前就得到一个EOFException
     * @throws InternalException         内部异常
     * @throws ErrorResponseException    执行失败
     * @throws InvalidResponseException
     * @throws ServerException
     * @throws XmlParserException
     */
    public Iterable<Result<Item>> listObjects(String bucketName, String prefix, Boolean recursive, Boolean useVersion1) throws IOException, InvalidKeyException, InvalidResponseException,
            InsufficientDataException, NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, ErrorResponseException {
        // 检查'mybucket'是否存在。
        boolean found = client.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
        if (found) {
            ListObjectsArgs.Builder args = ListObjectsArgs.builder().bucket(bucketName);
            // 列出存储桶里的对象
            Iterable<Result<Item>> myObjects;
            if (recursive != null && useVersion1 != null && StringUtils.hasLength(prefix))
                myObjects = client.listObjects(args.prefix(prefix).recursive(recursive).useApiVersion1(useVersion1).build());
            else if (StringUtils.hasLength(prefix) && recursive != null) {
                myObjects = client.listObjects(args.prefix(prefix).recursive(recursive).build());
            } else if (StringUtils.hasLength(prefix)) {
                myObjects = client.listObjects(args.prefix(prefix).build());
            } else {
                myObjects = client.listObjects(args.build());
            }
            return myObjects;
        }
        return null;
    }

    /**
     * 列出存储桶中被部分上传的对象
     *
     * @param bucketName 存储桶名称
     * @param prefix     对象名称的前缀，列出有该前缀的对象
     * @param recursive  是否递归查找，如果是false,就模拟文件夹结构查找
     * @return Iterable<Result < Upload>>    对象列表
     * @throws IOException               连接异常
     * @throws InvalidKeyException       不合法的access key或者secret key
     * @throws NoSuchAlgorithmException  找不到相应的签名算法
     * @throws InsufficientDataException 在读到相应length之前就得到一个EOFException
     * @throws InternalException         内部异常
     * @throws ErrorResponseException    执行失败
     * @throws InvalidResponseException
     * @throws ServerException
     * @throws XmlParserException
     */
//    public Iterable<Result<Upload>> listIncompleteUploads(String bucketName, String prefix, Boolean recursive) throws IOException, InvalidKeyException, InvalidResponseException,
//            InsufficientDataException, NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, ErrorResponseException {
//        // 检查'mybucket'是否存在。
//        boolean found = client.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
//        if (found) {
//            // 列出'mybucket'中所有未完成的multipart上传的的对象。
//            Iterable<Result<Upload>> myObjects = null;
//            if (StringUtils.hasLength(prefix) && recursive != null) {
//                client.listIncompleteUploads(bucketName, prefix, recursive);
//            } else if (StringUtils.hasLength(prefix)) {
//                client.listIncompleteUploads(bucketName, prefix);
//            } else {
//                client.listIncompleteUploads(bucketName);
//            }
//            return myObjects;
//        }
//        return null;
//    }

    /**
     * 获得指定对象前缀的存储桶策略
     *
     * @param bucketName 存储桶名称
     * @return PolicyType  存储桶策略
     * @throws IOException                   连接异常
     * @throws InvalidKeyException           不合法的access key或者secret key
     * @throws NoSuchAlgorithmException      找不到相应的签名算法
     * @throws InsufficientDataException     在读到相应length之前就得到一个EOFException
     * @throws InternalException             内部错误
     * @throws ErrorResponseException        执行失败异常
     * @throws InvalidResponseException
     * @throws BucketPolicyTooLargeException
     * @throws ServerException
     * @throws XmlParserException
     */
    public String getBucketPolicy(String bucketName) throws IOException, InvalidKeyException, InvalidResponseException,
            BucketPolicyTooLargeException, NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, InsufficientDataException, ErrorResponseException {
        String bucketPolicy = client.getBucketPolicy(GetBucketPolicyArgs.builder().bucket(bucketName).build());
        return bucketPolicy;
    }

    /**
     * 给一个存储桶+对象前缀设置策略
     *
     * @param bucketName 存储桶名称
     * @param policy     要赋予的策略，可选值有[PolicyType.NONE, PolicyType.READ_ONLY, PolicyType.READ_WRITE, PolicyType.WRITE_ONLY]
     * @throws IOException               连接异常
     * @throws InvalidKeyException       不合法的access key或者secret key
     * @throws NoSuchAlgorithmException  找不到相应的签名算法
     * @throws InsufficientDataException 在读到相应length之前就得到一个EOFException
     * @throws InternalException         内部错误
     * @throws ErrorResponseException    执行失败异常
     * @throws InvalidResponseException
     * @throws ServerException
     * @throws XmlParserException
     */
    public void setBucketPolicy(String bucketName, String policy) throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException,
            NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, ErrorResponseException {
        client.setBucketPolicy(SetBucketPolicyArgs.builder().bucket(bucketName).config(policy).build());
    }
}
